package com.dxy.df.core.exception;


import com.alibaba.fastjson.JSONObject;
import com.dxy.df.constants.ErrorEnum;
import com.dxy.df.core.model.Rs;
import com.dxy.df.utils.LogUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.TypeMismatchException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;

/**
 * 异常处理器
 */
@RestControllerAdvice
public class BizExceptionHandler {
    @Autowired
    private LogUtils logUtils;

    private static final Logger LOGGER = LoggerFactory.getLogger(BizExceptionHandler.class);

    private String tips = "参数不合法";

    /**
     * 自定义异常
     */
    @ExceptionHandler(BizException.class)
    public Rs handleRRException(BizException e) {
        Rs rs = Rs.error(e.getCode(), e.getMessage());
        logUtils.printRequestLog(JSONObject.toJSONString(rs));
        return rs;
    }


    @ExceptionHandler(BizBizException.class)
    public Rs handleBizBIZException(BizBizException e) {
        Rs rs = Rs.ok(e.getCode(), e.getMessage());
        logUtils.printRequestLog(JSONObject.toJSONString(rs));
        return rs;
    }

    @ExceptionHandler(DuplicateKeyException.class)
    public Rs handleDuplicateKeyException(DuplicateKeyException e) {
        LOGGER.error(e.getMessage(), e);
        Rs  rs=  Rs.error(ErrorEnum.HAS_EXIST);
        logUtils.printRequestLog(JSONObject.toJSONString(rs));
        return rs;
    }


    @ExceptionHandler(Exception.class)
    public Rs handleException(Exception e) {
        LOGGER.error(e.getMessage(), e);
        Rs rs =  Rs.error();
        logUtils.printRequestLog(JSONObject.toJSONString(rs));
        return rs;
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Rs handleIllegalParamException(MethodArgumentNotValidException e) {
        List<ObjectError> errors = e.getBindingResult().getAllErrors();
        if (!errors.isEmpty()) {
            tips = errors.get(0).getDefaultMessage();
        }
        Rs rs = Rs.error(HttpStatus.FORBIDDEN.value(), tips);
        logUtils.printRequestLog(JSONObject.toJSONString(rs));
        return rs;
    }

    @ExceptionHandler(BindException.class)
    public Rs bindException(BindException e) {
        List<ObjectError> errors = e.getBindingResult().getAllErrors();
        if (!errors.isEmpty()) {
            tips = errors.get(0).getDefaultMessage();
        }
        Rs rs = Rs.error(HttpStatus.BAD_REQUEST.value(), tips);
        logUtils.printRequestLog(JSONObject.toJSONString(rs));
        return rs;
    }

    @ExceptionHandler(ConstraintViolationException.class)
    public Rs constraintViolationException(ConstraintViolationException e) {
        Set<ConstraintViolation<?>> cves = e.getConstraintViolations();
        for (ConstraintViolation<?> constraintViolation : cves) {
            if (StringUtils.isEmpty(constraintViolation.getMessage())) {
                tips = constraintViolation.getMessage();
            }
        }
        Rs rs =  Rs.error(HttpStatus.FORBIDDEN.value(), tips);
        logUtils.printRequestLog(JSONObject.toJSONString(rs));
        return rs;
    }

    /**
     * 参数类型不匹配
     * getPropertyName()获取数据类型不匹配参数名称
     * getRequiredType()实际要求客户传递的数据类型
     */
    @ExceptionHandler({TypeMismatchException.class})
    public Rs requestTypeMismatch(TypeMismatchException ex) {
        if (null != ex.getPropertyName()) {
            tips = "参数类型不匹配,参数" + ex.getPropertyName() + "类型应该为" + ex.getRequiredType();
        } else {
            tips = "参数类型不匹配";
        }
        Rs rs = Rs.error(HttpStatus.BAD_REQUEST.value(), tips);
        logUtils.printRequestLog(JSONObject.toJSONString(rs));
        return rs;
    }

    @ExceptionHandler({MissingServletRequestParameterException.class})
    public Rs requestMissingServletRequest(MissingServletRequestParameterException ex) {
        tips = "参数类型不匹配,参数缺少必要参数,参数名称为" + ex.getParameterName();
        Rs rs = Rs.error(HttpStatus.BAD_REQUEST.value(), tips);
        logUtils.printRequestLog(JSONObject.toJSONString(rs));
        return rs;
    }

    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public Rs httpRequestMethodNotSupportedException(Throwable ex) {
        Rs rs = Rs.error(HttpStatus.BAD_REQUEST.value(), ex.getMessage());
        logUtils.printRequestLog(JSONObject.toJSONString(rs));
        return rs;
    }


    @ExceptionHandler({HttpMessageNotReadableException.class})
    public Rs httpMediaTypeNotSupportedException(Throwable ex) {
        Rs rs = Rs.error(HttpStatus.BAD_REQUEST.value(), ex.getMessage());
        logUtils.printRequestLog(JSONObject.toJSONString(rs));
        return rs;
    }



}
